package com.atguigu.gmall.order.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.gmall.common.constant.MqConst;
import com.atguigu.gmall.common.service.RabbitService;
import com.atguigu.gmall.common.util.HttpClientUtil;
import com.atguigu.gmall.model.enums.OrderStatus;
import com.atguigu.gmall.model.enums.PaymentStatus;
import com.atguigu.gmall.model.enums.ProcessStatus;
import com.atguigu.gmall.model.order.OrderDetail;
import com.atguigu.gmall.model.order.OrderInfo;
import com.atguigu.gmall.order.mapper.OrderDetailMapper;
import com.atguigu.gmall.order.mapper.OrderInfoMapper;
import com.atguigu.gmall.order.service.OrderService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;

@Service
public class OrderServiceImpl extends ServiceImpl<OrderInfoMapper,OrderInfo>implements OrderService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RabbitService rabbitService;

    @Value("${ware.url}")
    private String wareUrl;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long saveOrderInfo(OrderInfo orderInfo) {
        //赋值前端未传递的数据
        orderInfo.sumTotalAmount();
        orderInfo.setOrderStatus(OrderStatus.UNPAID.name());
        String outTradeNo = "ATGUIGU" + System.currentTimeMillis() + "" + new Random().nextInt(1000);
        orderInfo.setOutTradeNo(outTradeNo);
        orderInfo.setCreateTime(new Date());
        orderInfo.setTradeBody("购买小分队.....");
        orderInfo.setOperateTime(new Date());

        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE,1);
        orderInfo.setExpireTime(calendar.getTime());
        orderInfo.setProcessStatus(ProcessStatus.UNPAID.name());

        orderInfoMapper.insert(orderInfo);

        Long orderId = orderInfo.getId();

        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        if(!CollectionUtils.isEmpty(orderDetailList)){
            for (OrderDetail orderDetail : orderDetailList) {
                orderDetail.setOrderId(orderId);
                orderDetailMapper.insert(orderDetail);
            }
        }

        rabbitService.sendDelayMessage(MqConst.EXCHANGE_DIRECT_ORDER_CANCEL,MqConst.ROUTING_ORDER_CANCEL,orderId,MqConst.DELAY_TIME);

        return orderId;
    }

    @Override
    public String getTradeNo(String userId) {
        String tradeNo = UUID.randomUUID().toString();
        //放入缓存
        String tradeNoKey = "trade:" + userId;
        redisTemplate.opsForValue().set(tradeNoKey,tradeNo);
        return tradeNo;
    }

    @Override
    public boolean checkTradeNo(String tradeNo,String userId) {
        String tradeNoRedis = (String) redisTemplate.opsForValue().get("trade:" + userId);
        return tradeNoRedis.equals(tradeNo);
    }

    @Override
    public void deleteTradeNo(String userId) {
        redisTemplate.delete("trade:" + userId);
    }

    @Override
    public boolean checkStock(Long skuId, Integer skuNum) {
        String result = HttpClientUtil.doGet(wareUrl + "/hasStock?skuId=" + skuId + "&num=" + skuNum);
        return "1".equals(result);
    }

    @Override
    public IPage getOrderList(Page<OrderInfo> orderInfoPage, String userId) {
        IPage<OrderInfo> iPage = orderInfoMapper.selectOrderList(orderInfoPage,userId);
        return iPage;
    }

    @Override
    public void execExpiredOrder(Long orderId) {
        this.updateOrderStatus(orderId,ProcessStatus.CLOSED);
        //orderInfo状态更新后给paymentInfo发个消息，更新状态
        rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_PAYMENT_CLOSE,MqConst.EXCHANGE_DIRECT_PAYMENT_CLOSE,orderId);
    }

    public void updateOrderStatus(Long orderId, ProcessStatus closed) {
        OrderInfo orderInfo = new OrderInfo();
        orderInfo.setId(orderId);
        orderInfo.setProcessStatus(closed.name());
        orderInfo.setOrderStatus(closed.getOrderStatus().name());
        orderInfoMapper.updateById(orderInfo);
    }

    @Override
    public OrderInfo getOrderInfo(Long orderId) {
        OrderInfo orderInfo = orderInfoMapper.selectById(orderId);
        List<OrderDetail> orderDetailList = orderDetailMapper.selectList(new QueryWrapper<OrderDetail>().eq("order_id", orderId));
        orderInfo.setOrderDetailList(orderDetailList);
        return orderInfo;
    }

    @Override
    public void sendOrderStatus(Long orderId) {
        this.updateOrderStatus(orderId, ProcessStatus.NOTIFIED_WARE);
        OrderInfo orderInfo = this.getOrderInfo(orderId);

        Map map = this.initWare(orderInfo);

        rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_WARE_STOCK,MqConst.ROUTING_WARE_STOCK,JSON.toJSONString(map));
    }

    @Override
    public Map initWare(OrderInfo orderInfo) {
        //orderId consignee consigneeTel orderComment orderBody deliveryAddress paymentWay
        Map<String, Object> map = new HashMap<>();
        map.put("orderId",orderInfo.getId());
        map.put("consignee",orderInfo.getConsignee());
        map.put("consigneeTel",orderInfo.getConsigneeTel());
        map.put("orderComment",orderInfo.getOrderComment());
        map.put("orderBody",orderInfo.getTradeBody());
        map.put("deliveryAddress",orderInfo.getDeliveryAddress());
        map.put("paymentWay",orderInfo.getPaymentWay());
        map.put("wareId",orderInfo.getWareId());

        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        ArrayList<Map> list = new ArrayList<>();
        for (OrderDetail orderDetail : orderDetailList) {
            HashMap<String, Object> orderDetailMap = new HashMap<>();
            orderDetailMap.put("skuId",orderDetail.getSkuId());
            orderDetailMap.put("skuNum",orderDetail.getSkuNum());
            orderDetailMap.put("skuName",orderDetail.getSkuName());
            list.add(orderDetailMap);
        }
        map.put("details",list);

       return map;
    }

    @Override
    public List<OrderInfo> orderSplit(Long orderId, String strMap) {
        /*
        1、先获取到原始订单
        2.  将wareSkuMap 转换为我们能操作的对象map  [{"wareId":"1","skuIds":["2","10"]},{"wareId":"2","skuIds":["3"]}]
        3.  创建一个新的子订单
        4.  给子订单赋值
        5.  保存子订单到数据库
        6.  修改原始订单的状态
         */
        //获取订单数据
        OrderInfo orderInfo = this.getOrderInfo(orderId);

        //声明一个子订单集合
        List<OrderInfo> subOrderInfoList = new ArrayList<>();

        List<Map> maps = JSON.parseArray(strMap, Map.class);
        for (Map map : maps) {
            String wareId = (String) map.get("wareId");
            List<String> skuIds = (List<String>) map.get("skuIds");

            //创建子订单对象
            OrderInfo subOrderInfo = new OrderInfo();
            //给子订单赋值
            BeanUtils.copyProperties(orderInfo,subOrderInfo);
            subOrderInfo.setId(null);
            subOrderInfo.setParentOrderId(orderId);
            subOrderInfo.setWareId(wareId);
            //获取订单明细集合
            List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();

            //创建子订单明细集合
            ArrayList<OrderDetail> subOrderDetailList = new ArrayList<>();
            for (OrderDetail orderDetail : orderDetailList) {
                for (String skuId : skuIds) {
                    if(Long.parseLong(skuId) == orderDetail.getSkuId()){
                        subOrderDetailList.add(orderDetail);
                    }
                }
            }

            subOrderInfo.setOrderDetailList(subOrderDetailList);

            //保存数据库
            this.saveOrderInfo(subOrderInfo);
            subOrderInfoList.add(subOrderInfo);
        }

        this.updateOrderStatus(orderId,ProcessStatus.SPLIT);

        return subOrderInfoList;
    }

    @Override
    public void execExpiredOrder(Long orderId, String flag) {
        this.updateOrderStatus(orderId,ProcessStatus.CLOSED);
        if("2".equals(flag)){//关闭paymentInfo
            rabbitService.sendMessage(MqConst.EXCHANGE_DIRECT_PAYMENT_CLOSE,MqConst.ROUTING_PAYMENT_CLOSE,orderId);
        }
    }
}
